/*
 * COPYRIGHT. ShenZhen JiMi Technology Co., Ltd. 2017.
 * ALL RIGHTS RESERVED.
 *
 * No part of this publication may be reproduced, stored in a retrieval system, or transmitted,
 * on any form or by any means, electronic, mechanical, photocopying, recording, 
 * or otherwise, without the prior written permission of ShenZhen JiMi Network Technology Co., Ltd.
 *
 * Amendment History:
 * 
 * Date                   By              Description
 * -------------------    -----------     -------------------------------------------
 * 2017年4月28日    li.shangzhi         Create the class
 * http://www.jimilab.com/
 */

package com.jimi.gateway.filter.openapi.post;

import java.io.IOException;
import java.io.InputStream;

import javax.servlet.http.HttpServletRequest;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.alibaba.fastjson.JSONObject;
import com.jimi.app.api.IApiAppAccessingLogApi;
import com.jimi.app.dto.input.ApiAppAccessingLogInputDto;
import com.jimi.app.dto.output.ApiAppInfoOutputDto;
import com.jimi.app.dto.output.ApiOpenFunctionsOutputDto;
import com.jimi.framework.context.SpringContextHolder;
import com.jimi.gateway.utils.Constants;
import com.jimi.gateway.utils.InputStreamCacher;
import com.jimi.gateway.utils.ResultModel;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;

/**
 * @FileName AccessingLogFilter.java
 * @Description: Open Api网关记录请求访问日志，数据入库
 *
 * @Date 2017年4月28日 上午11:48:59
 * @author li.shangzhi
 * @version 1.0
 */
public class AccessingLogFilter extends ZuulFilter {

	private static final int FILTER_ORDER = 1;
	
	private final Logger logger = LoggerFactory.getLogger(AccessingLogFilter.class);

	@Override
	public boolean shouldFilter() {
		RequestContext ctx = RequestContext.getCurrentContext();
		String routeId = String.valueOf(ctx.get("proxy"));
		if (!Constants.OPEN_API_NAMESPACE.equals(routeId)) {
			return false;
		}
		return (ctx.getResponseDataStream() != null || ctx.getResponseBody() != null) && ctx.getBoolean(Constants.IS_NEXT_FILTER, true);
	}

	@Override
	public Object run() {
		RequestContext ctx = RequestContext.getCurrentContext();
		HttpServletRequest requeset = ctx.getRequest();
		String requestIp = ctx.getZuulRequestHeaders().get("x-forwarded-for");
		ApiAppInfoOutputDto appInfoDto = (ApiAppInfoOutputDto) ctx.get(Constants.APP_INFO);
		ApiOpenFunctionsOutputDto openFunDto = (ApiOpenFunctionsOutputDto) ctx.get(Constants.OPEN_FUNCTION);
		
		ApiAppAccessingLogInputDto logInputDto = new ApiAppAccessingLogInputDto();
		logInputDto.setRemoteIp(requestIp);
		logInputDto.setAppKey(appInfoDto.getAppKey());
		logInputDto.setUserId(appInfoDto.getUserId());
		logInputDto.setAccount(appInfoDto.getAccount());
		
		logInputDto.setRouteId(openFunDto.getRouteId());
		logInputDto.setMethod(openFunDto.getMethod());
		logInputDto.setPath(openFunDto.getUrl());
		
		ResultModel resultModel = null;
		if(ctx.getResponseBody() != null) {
			resultModel = JSONObject.parseObject(ctx.getResponseBody(), ResultModel.class);
		} else {
			InputStreamCacher ioCacher = new InputStreamCacher(ctx.getResponseDataStream());
			InputStream is = ioCacher.getInputStream();
			if(null != is) {
				try {
					resultModel = JSONObject.parseObject(is, ResultModel.class);
				} catch (IOException e) {
					logger.error("JSONObject解析ResponseDataStream流出错。", e);
				} finally {
					ctx.setResponseDataStream(ioCacher.getInputStream()); // 把结果数据在放回去，让SendResponseFilter过滤器执行
					ioCacher.close();
				}
			}
		}
		if (null == resultModel) {
			// 默认成功
			logInputDto.setStatus(true);
		} else {
			if (resultModel.getCode() == 0) {
				// 成功
				logInputDto.setStatus(true);
			} else {
				logInputDto.setStatus(false);
				logInputDto.setErrorDesc(resultModel.getMessage());
			}
		}
		
		if (!openFunDto.getAuth()) { // 不需要认证的接口
			logInputDto.setUseAccount(requeset.getParameter("user_id"));
		} else {
			// 其他接口
			logInputDto.setUseAccount(ctx.get(Constants.USE_ACCOUNT).toString());
		}
		IApiAppAccessingLogApi apiAppAccessingLogApi = SpringContextHolder.getBean(IApiAppAccessingLogApi.class);
		apiAppAccessingLogApi.insert(logInputDto);
		return null;
	}

	@Override
	public String filterType() {
		return Constants.POST_FILTER;
	}

	@Override
	public int filterOrder() {
		return FILTER_ORDER;
	}

}
